{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "89590a8a-e16f-4381-b67b-7484424eeffd",
   "metadata": {
    "collapsed": true,
    "jupyter": {
     "outputs_hidden": true
    }
   },
   "source": [
    "### "
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3e3e722d-2557-4f45-a96a-021b000ce757",
   "metadata": {},
   "source": [
    "### **BeautifulSoup 使用课件**\n",
    "\n",
    "#### 课程目标：\n",
    "\n",
    "通过本次课，学生将学习如何使用 `BeautifulSoup` 库来解析 HTML 文档，提取有用的内容。课程将涵盖 `BeautifulSoup` 的基础用法、元素查找、文档树遍历及实际应用示例。\n",
    "\n",
    "---\n",
    "\n",
    "### **1. 什么是 BeautifulSoup？**\n",
    "\n",
    "`BeautifulSoup` 是 Python 的一个库，用于从 HTML 或 XML 文档中提取数据。它将复杂的 HTML 文档转换为易于处理的 Python 对象，如标签、列表等。常用于网络爬虫的数据解析。\n",
    "\n",
    "---\n",
    "\n",
    "### **2. 环境设置**\n",
    "\n",
    "- 安装 `BeautifulSoup4`：\n",
    "\n",
    "  ```bash\n",
    "  pip install beautifulsoup4\n",
    "  pip install lxml\n",
    "  ```\n",
    "\n",
    "  **说明**：\n",
    "\n",
    "  - `beautifulsoup4` 是解析 HTML 的核心库。\n",
    "  - `lxml` 是 HTML 解析器，推荐用于高效、宽容的解析。\n",
    "\n",
    "---\n",
    "\n",
    "### **3. BeautifulSoup 的基本使用方法**\n",
    "\n",
    "通过 `BeautifulSoup`，我们可以非常方便地解析和提取 HTML 文档中的数据。\n",
    "\n",
    "#### 例子：解析 HTML 文档"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7e0acd1d-c2fc-40c1-978a-c5eb48355082",
   "metadata": {},
   "source": [
    "from bs4 import BeautifulSoup\n",
    "\n",
    "# 示例 HTML 内容\n",
    "html_content = '''\n",
    "<html>\n",
    "  <head>\n",
    "    <title>示例页面</title>\n",
    "  </head>\n",
    "  <body>\n",
    "    <h1>欢迎来到示例页面</h1>\n",
    "    <div class=\"movie\">\n",
    "        <h2>电影名称: 夺冠</h2>\n",
    "        <span class=\"rating_num\">8.5</span>\n",
    "    </div>\n",
    "    <div class=\"movie\">\n",
    "        <h2>电影名称: 八佰</h2>\n",
    "        <span class=\"rating_num\">7.9</span>\n",
    "    </div>\n",
    "  </body>\n",
    "</html>\n",
    "'''\n",
    "\n",
    "# 创建 BeautifulSoup 对象并解析 HTML 内容\n",
    "soup = BeautifulSoup(html_content, 'lxml')\n",
    "\n",
    "# 查找网页标题\n",
    "page_title = soup.title.text\n",
    "print(f\"页面标题: {page_title}\")\n",
    "\n",
    "# 查找第一个 <h1> 标签的内容\n",
    "h1_text = soup.h1.text\n",
    "print(f\"主标题: {h1_text}\")\n",
    "\n",
    "# 查找所有电影信息\n",
    "movies = soup.find_all('div', class_='movie')\n",
    "\n",
    "for movie in movies:\n",
    "    # 提取电影名称\n",
    "    title = movie.find('h2').text\n",
    "    # 提取电影评分\n",
    "    rating = movie.find('span', class_='rating_num').text\n",
    "    print(f\"电影: {title}, 评分: {rating}\")\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "74370e8f-584b-49eb-9427-ca1f157a1a25",
   "metadata": {},
   "source": [
    "### **4. 查找 HTML 元素**\n",
    "\n",
    "#### **4.1 使用 `find()` 查找单个元素**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "78a1280e-e3f1-453d-ae1e-81516a0110bb",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "第一个电影标题: 电影名称: 夺冠\n"
     ]
    }
   ],
   "source": [
    "# 查找第一个 <h2> 标签\n",
    "first_h2 = soup.find('h2').text\n",
    "print(f\"第一个电影标题: {first_h2}\")\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3f8330c8-fde0-4db5-9685-08cfb4ccd592",
   "metadata": {},
   "source": [
    "**4.2 使用 `find_all()` 查找所有符合条件的元素**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "670ffcba-a721-47bf-8f00-94c2aaca7dd7",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "电影名称: 电影名称: 夺冠\n",
      "电影名称: 电影名称: 八佰\n"
     ]
    }
   ],
   "source": [
    "# 查找所有电影的标题\n",
    "all_h2 = soup.find_all('h2')\n",
    "for movie in all_h2:\n",
    "    print(f\"电影名称: {movie.text}\")\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ac90d4be-cf8b-4c56-b69f-88d18da81bdd",
   "metadata": {},
   "source": [
    "**4.3 查找特定属性的元素**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "645ca987-9e87-4e2a-b558-77d82190a60d",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "评分: 8.5\n",
      "评分: 7.9\n"
     ]
    }
   ],
   "source": [
    "# 查找所有评分\n",
    "ratings = soup.find_all('span', class_='rating_num')\n",
    "for rating in ratings:\n",
    "    print(f\"评分: {rating.text}\")\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "251e1dba-eb1b-4ed2-9a25-b4de5c3d8078",
   "metadata": {},
   "source": [
    "### **5. 遍历文档树**\n",
    "\n",
    "- `.parent`：找到当前标签的父节点\n",
    "- `.children`：遍历当前标签的子节点\n",
    "- `.next_sibling` / `.previous_sibling`：查找兄弟节点"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "523d8f1e-2538-4cab-ad4b-ea725f56f4b4",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "父标签: div\n",
      "\n",
      "\n",
      "<h2>电影名称: 夺冠</h2>\n",
      "\n",
      "\n",
      "<span class=\"rating_num\">8.5</span>\n",
      "\n",
      "\n"
     ]
    }
   ],
   "source": [
    "# 查找 <h2> 标签的父节点\n",
    "parent_tag = soup.h2.parent\n",
    "print(f\"父标签: {parent_tag.name}\")\n",
    "\n",
    "# 遍历 <div> 标签中的子节点\n",
    "div_tag = soup.div\n",
    "for child in div_tag.children:\n",
    "    print(child)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f06f4653-af7d-48ee-b1db-e63a6c91370e",
   "metadata": {},
   "source": [
    "### **6. 提取标签内容和属性**\n",
    "\n",
    "#### **6.1 获取标签中的纯文本**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "c249d19a-4273-497b-8c13-03a13927e272",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "电影名称: 电影名称: 夺冠\n"
     ]
    }
   ],
   "source": [
    "# 获取第一个电影标题中的文本\n",
    "movie_title = soup.h2.get_text()\n",
    "print(f\"电影名称: {movie_title}\")\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a19fd9ba-611d-4441-8e6e-789853d144ec",
   "metadata": {},
   "source": [
    "**6.2 提取标签属性**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "02c34f80-8f4f-41dc-982f-d63080cf8c63",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "链接: https://example.com\n",
      "链接: https://another.com\n"
     ]
    }
   ],
   "source": [
    "# 示例 HTML 中的链接\n",
    "html_with_links = '''\n",
    "<a href=\"https://example.com\">Example</a>\n",
    "<a href=\"https://another.com\">Another Example</a>\n",
    "'''\n",
    "\n",
    "soup_links = BeautifulSoup(html_with_links, 'lxml')\n",
    "links = soup_links.find_all('a')\n",
    "\n",
    "# 提取每个链接的 href 属性\n",
    "for link in links:\n",
    "    print(f\"链接: {link.get('href')}\")\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "e00042e4-eb27-4d72-9c1b-8f9a7888b569",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "电影: 肖申克的救赎\n",
      "评分: 9.7\n",
      "导演: 导演: 弗兰克·德拉邦特 Frank Darabont   主演: 蒂姆·罗宾斯 Tim Robbins /...\n",
      "简评: 希望让人自由。\n",
      "----------------------------------------\n",
      "电影: 霸王别姬\n",
      "评分: 9.6\n",
      "导演: 导演: 陈凯歌 Kaige Chen   主演: 张国荣 Leslie Cheung / 张丰毅 Fengyi Zha...\n",
      "简评: 风华绝代。\n",
      "----------------------------------------\n",
      "电影: 阿甘正传\n",
      "评分: 9.5\n",
      "导演: 导演: 罗伯特·泽米吉斯 Robert Zemeckis   主演: 汤姆·汉克斯 Tom Hanks / ...\n",
      "简评: 一部美国近现代史。\n",
      "----------------------------------------\n",
      "电影: 泰坦尼克号\n",
      "评分: 9.5\n",
      "导演: 导演: 詹姆斯·卡梅隆 James Cameron   主演: 莱昂纳多·迪卡普里奥 Leonardo...\n",
      "简评: 失去的才是永恒的。 \n",
      "----------------------------------------\n",
      "电影: 千与千寻\n",
      "评分: 9.4\n",
      "导演: 导演: 宫崎骏 Hayao Miyazaki   主演: 柊瑠美 Rumi Hîragi / 入野自由 Miy...\n",
      "简评: 最好的宫崎骏，最好的久石让。 \n",
      "----------------------------------------\n",
      "电影: 这个杀手不太冷\n",
      "评分: 9.4\n",
      "导演: 导演: 吕克·贝松 Luc Besson   主演: 让·雷诺 Jean Reno / 娜塔莉·波特曼 ...\n",
      "简评: 怪蜀黍和小萝莉不得不说的故事。\n",
      "----------------------------------------\n",
      "电影: 美丽人生\n",
      "评分: 9.5\n",
      "导演: 导演: 罗伯托·贝尼尼 Roberto Benigni   主演: 罗伯托·贝尼尼 Roberto Beni...\n",
      "简评: 最美的谎言。\n",
      "----------------------------------------\n",
      "电影: 星际穿越\n",
      "评分: 9.4\n",
      "导演: 导演: 克里斯托弗·诺兰 Christopher Nolan   主演: 马修·麦康纳 Matthew Mc...\n",
      "简评: 爱是一种力量，让我们超越时空感知它的存在。\n",
      "----------------------------------------\n",
      "电影: 盗梦空间\n",
      "评分: 9.4\n",
      "导演: 导演: 克里斯托弗·诺兰 Christopher Nolan   主演: 莱昂纳多·迪卡普里奥 Le...\n",
      "简评: 诺兰给了我们一场无法盗取的梦。\n",
      "----------------------------------------\n",
      "电影: 楚门的世界\n",
      "评分: 9.4\n",
      "导演: 导演: 彼得·威尔 Peter Weir   主演: 金·凯瑞 Jim Carrey / 劳拉·琳妮 Lau...\n",
      "简评: 如果再也不能见到你，祝你早安，午安，晚安。\n",
      "----------------------------------------\n",
      "电影: 辛德勒的名单\n",
      "评分: 9.5\n",
      "导演: 导演: 史蒂文·斯皮尔伯格 Steven Spielberg   主演: 连姆·尼森 Liam Neeson...\n",
      "简评: 拯救一个人，就是拯救整个世界。\n",
      "----------------------------------------\n",
      "电影: 忠犬八公的故事\n",
      "评分: 9.4\n",
      "导演: 导演: 莱塞·霍尔斯道姆 Lasse Hallström   主演: 理查·基尔 Richard Ger...\n",
      "简评: 永远都不能忘记你所爱的人。\n",
      "----------------------------------------\n",
      "电影: 海上钢琴师\n",
      "评分: 9.3\n",
      "导演: 导演: 朱塞佩·托纳多雷 Giuseppe Tornatore   主演: 蒂姆·罗斯 Tim Roth / ...\n",
      "简评: 每个人都要走一条自己坚定了的路，就算是粉身碎骨。 \n",
      "----------------------------------------\n",
      "电影: 三傻大闹宝莱坞\n",
      "评分: 9.2\n",
      "导演: 导演: 拉库马·希拉尼 Rajkumar Hirani   主演: 阿米尔·汗 Aamir Khan / 卡...\n",
      "简评: 英俊版憨豆，高情商版谢耳朵。\n",
      "----------------------------------------\n",
      "电影: 放牛班的春天\n",
      "评分: 9.3\n",
      "导演: 导演: 克里斯托夫·巴拉蒂 Christophe Barratier   主演: 让-巴蒂斯特·莫尼...\n",
      "简评: 天籁一般的童声，是最接近上帝的存在。 \n",
      "----------------------------------------\n",
      "电影: 机器人总动员\n",
      "评分: 9.3\n",
      "导演: 导演: 安德鲁·斯坦顿 Andrew Stanton   主演: 本·贝尔特 Ben Burtt / 艾丽...\n",
      "简评: 小瓦力，大人生。\n",
      "----------------------------------------\n",
      "电影: 疯狂动物城\n",
      "评分: 9.2\n",
      "导演: 导演: 拜伦·霍华德 Byron Howard / 瑞奇·摩尔 Rich Moore   主演: 金妮弗·...\n",
      "简评: 迪士尼给我们营造的乌托邦就是这样，永远善良勇敢，永远出乎意料。\n",
      "----------------------------------------\n",
      "电影: 无间道\n",
      "评分: 9.3\n",
      "导演: 导演: 刘伟强 / 麦兆辉   主演: 刘德华 Andy Lau / 梁朝伟 Tony Leung Chiu W...\n",
      "简评: 香港电影史上永不过时的杰作。\n",
      "----------------------------------------\n",
      "电影: 控方证人\n",
      "评分: 9.6\n",
      "导演: 导演: 比利·怀尔德 Billy Wilder   主演: 泰隆·鲍华 Tyrone Power / 玛琳·...\n",
      "简评: 比利·怀德满分作品。\n",
      "----------------------------------------\n",
      "电影: 大话西游之大圣娶亲\n",
      "评分: 9.2\n",
      "导演: 导演: 刘镇伟 Jeffrey Lau   主演: 周星驰 Stephen Chow / 吴孟达 Man Tat Ng...\n",
      "简评: 一生所爱。\n",
      "----------------------------------------\n",
      "电影: 熔炉\n",
      "评分: 9.3\n",
      "导演: 导演: 黄东赫 Dong-hyuk Hwang   主演: 孔侑 Yoo Gong / 郑有美 Yu-mi Jung /...\n",
      "简评: 我们一路奋战不是为了改变世界，而是为了不让世界改变我们。\n",
      "----------------------------------------\n",
      "电影: 教父\n",
      "评分: 9.3\n",
      "导演: 导演: 弗朗西斯·福特·科波拉 Francis Ford Coppola   主演: 马龙·白兰度 M...\n",
      "简评: 千万不要记恨你的对手，这样会让你失去理智。\n",
      "----------------------------------------\n",
      "电影: 触不可及\n",
      "评分: 9.3\n",
      "导演: 导演: 奥利维·那卡什 Olivier Nakache / 艾力克·托兰达 Eric Toledano   主...\n",
      "简评: 满满温情的高雅喜剧。\n",
      "----------------------------------------\n",
      "电影: 当幸福来敲门\n",
      "评分: 9.2\n",
      "导演: 导演: 加布里尔·穆奇诺 Gabriele Muccino   主演: 威尔·史密斯 Will Smith ...\n",
      "简评: 平民励志片。 \n",
      "----------------------------------------\n",
      "电影: 寻梦环游记\n",
      "评分: 9.1\n",
      "导演: 导演: 李·昂克里奇 Lee Unkrich / 阿德里安·莫利纳 Adrian Molina   主演: ...\n",
      "简评: 死亡不是真的逝去，遗忘才是永恒的消亡。\n",
      "----------------------------------------\n"
     ]
    }
   ],
   "source": [
    "from bs4 import BeautifulSoup\n",
    "import requests\n",
    "\n",
    "# 设置请求的 URL\n",
    "url = \"https://movie.douban.com/top250\"\n",
    "\n",
    "# 定义请求头，模拟浏览器\n",
    "headers = {\n",
    "    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'\n",
    "}\n",
    "\n",
    "# 发送 GET 请求，获取页面内容\n",
    "response = requests.get(url, headers=headers)\n",
    "\n",
    "# 检查请求是否成功\n",
    "if response.status_code == 200:\n",
    "    html_content = response.text  # 获取网页 HTML 内容\n",
    "    \n",
    "    # 使用 BeautifulSoup 解析 HTML 内容\n",
    "    soup = BeautifulSoup(html_content, 'lxml')\n",
    "    \n",
    "    # 查找所有的电影条目\n",
    "    movies = soup.find_all('div', class_='item')\n",
    "    \n",
    "    # 遍历每个电影条目，提取相关信息\n",
    "    for movie in movies:\n",
    "        # 提取电影标题\n",
    "        title = movie.find('span', class_='title').text\n",
    "        \n",
    "        # 提取评分\n",
    "        rating = movie.find('span', class_='rating_num').text\n",
    "        \n",
    "        # 提取导演和主演信息\n",
    "        director = movie.find('p').text.strip().split('\\n')[0].strip()\n",
    "        \n",
    "        # 提取简短评论，如果有的话\n",
    "        quote = movie.find('span', class_='inq')\n",
    "        if quote:\n",
    "            quote = quote.text\n",
    "        else:\n",
    "            quote = \"暂无简评\"\n",
    "        \n",
    "        # 输出电影信息\n",
    "        print(f\"电影: {title}\")\n",
    "        print(f\"评分: {rating}\")\n",
    "        print(f\"导演: {director}\")\n",
    "        print(f\"简评: {quote}\")\n",
    "        print(\"-\" * 40)\n",
    "\n",
    "else:\n",
    "    print(f\"请求失败，状态码: {response.status_code}\")\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2bc6f385-2be8-4361-a308-2c05bcb7cb90",
   "metadata": {},
   "source": [
    "### 代码解析：\n",
    "\n",
    "1. **请求页面**：通过 `requests.get` 发送 GET 请求到豆瓣的 `Top 250` 页面，并模拟一个浏览器的请求头，以防止被阻止。\n",
    "2. **解析 HTML**：使用 `BeautifulSoup` 解析 HTML 内容，并提取电影条目列表。\n",
    "3. **提取信息**：\n",
    "   - **电影标题**：通过查找 `span` 标签，提取其中的电影标题。\n",
    "   - **评分**：通过 `span` 标签中的 `class_='rating_num'`，提取评分信息。\n",
    "   - **导演及主演**：通过电影条目中的 `<p>` 标签提取导演和主演的信息。\n",
    "   - **简评**：尝试查找 `span` 标签中的简评内容，如果没有，则显示 \"暂无简评\"。\n",
    "4. **输出**：打印每部电影的详细信息，包括标题、评分、导演和简评。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "372158fa-95c3-438e-90aa-9b0f2efc28f0",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "电影名称: 肖申克的救赎\n",
      "电影名称:  / The Shawshank Redemption\n",
      "电影名称: 霸王别姬\n",
      "电影名称: 阿甘正传\n",
      "电影名称:  / Forrest Gump\n",
      "电影名称: 泰坦尼克号\n",
      "电影名称:  / Titanic\n",
      "电影名称: 千与千寻\n",
      "电影名称:  / 千と千尋の神隠し\n",
      "电影名称: 这个杀手不太冷\n",
      "电影名称:  / Léon\n",
      "电影名称: 美丽人生\n",
      "电影名称:  / La vita è bella\n",
      "电影名称: 星际穿越\n",
      "电影名称:  / Interstellar\n",
      "电影名称: 盗梦空间\n",
      "电影名称:  / Inception\n",
      "电影名称: 楚门的世界\n",
      "电影名称:  / The Truman Show\n",
      "电影名称: 辛德勒的名单\n",
      "电影名称:  / Schindler's List\n",
      "电影名称: 忠犬八公的故事\n",
      "电影名称:  / Hachi: A Dog's Tale\n",
      "电影名称: 海上钢琴师\n",
      "电影名称:  / La leggenda del pianista sull'oceano\n",
      "电影名称: 三傻大闹宝莱坞\n",
      "电影名称:  / 3 Idiots\n",
      "电影名称: 放牛班的春天\n",
      "电影名称:  / Les choristes\n",
      "电影名称: 机器人总动员\n",
      "电影名称:  / WALL·E\n",
      "电影名称: 疯狂动物城\n",
      "电影名称:  / Zootopia\n",
      "电影名称: 无间道\n",
      "电影名称:  / 無間道\n",
      "电影名称: 控方证人\n",
      "电影名称:  / Witness for the Prosecution\n",
      "电影名称: 大话西游之大圣娶亲\n",
      "电影名称:  / 西遊記大結局之仙履奇緣\n",
      "电影名称: 熔炉\n",
      "电影名称:  / 도가니\n",
      "电影名称: 教父\n",
      "电影名称:  / The Godfather\n",
      "电影名称: 触不可及\n",
      "电影名称:  / Intouchables\n",
      "电影名称: 当幸福来敲门\n",
      "电影名称:  / The Pursuit of Happyness\n",
      "电影名称: 寻梦环游记\n",
      "电影名称:  / Coco\n"
     ]
    }
   ],
   "source": [
    "from bs4 import BeautifulSoup\n",
    "import requests\n",
    "\n",
    "# 设置请求的 URL\n",
    "url = \"https://movie.douban.com/top250\"\n",
    "\n",
    "# 定义请求头，模拟浏览器\n",
    "headers = {\n",
    "    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'\n",
    "}\n",
    "\n",
    "# 发送 GET 请求，获取页面内容\n",
    "response = requests.get(url, headers=headers)\n",
    "\n",
    "# 检查请求是否成功\n",
    "if response.status_code == 200:\n",
    "    html_content = response.text  # 获取网页 HTML 内容\n",
    "    \n",
    "    # 使用 BeautifulSoup 解析 HTML 内容\n",
    "    soup = BeautifulSoup(html_content, 'lxml')\n",
    "    \n",
    "    # 使用 CSS 选择器提取所有电影的标题\n",
    "    movie_titles = soup.select('#content div.article ol li div.info div.hd a span.title')\n",
    "    \n",
    "    # 打印所有提取到的电影标题\n",
    "    for title in movie_titles:\n",
    "        print(f\"电影名称: {title.text}\")\n",
    "else:\n",
    "    print(f\"请求失败，状态码: {response.status_code}\")\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3ecb37ef-2868-404a-9d1f-9e3e29a0f581",
   "metadata": {},
   "source": [
    "两个 CSS 选择器中，分别针对页面中的第一个和第二个电影标题进行定位。通过分析这两个选择器，我们可以推导出所有电影标题的通用选择器。以下是对这两个选择器的解释，并解释如何推导出通用的选择器来提取所有的电影标题。\n",
    "\n",
    "### 选择器 1 和 2：\n",
    "\n",
    "- **选择器 1**: `#content > div > div.article > ol > li:nth-child(1) > div > div.info > div.hd > a > span:nth-child(1)`\n",
    "  - 这个选择器用于提取第一个电影的标题。\n",
    "  - `nth-child(1)` 是关键，它表示在页面中的第一个电影条目。\n",
    "  - `span:nth-child(1)` 选择的是电影标题的 `span` 标签。\n",
    "\n",
    "- **选择器 2**: `#content > div > div.article > ol > li:nth-child(2) > div > div.info > div.hd > a > span.title`\n",
    "  - 这个选择器用于提取第二个电影的标题。\n",
    "  - `nth-child(2)` 表示第二个电影条目。\n",
    "  - `span.title` 用于选择标题的 `span` 标签，它是 `.title` 类名的 `span`。\n",
    "\n",
    "### 通用选择器的推导：\n",
    "\n",
    "#### 分析关键部分：\n",
    "\n",
    "- `#content > div > div.article > ol > li:nth-child(n) > div > div.info > div.hd > a > span.title`\n",
    "  - `#content > div > div.article > ol > li`：`li` 代表每个电影条目，它位于 `ol` 标签中，并包含多个 `li` 项。\n",
    "  - `div.info`：这是每个电影条目的包含电影信息的 `div`。\n",
    "  - `div.hd > a > span.title`：这是包含电影标题的元素路径。\n",
    "\n",
    "#### 观察共同点：\n",
    "\n",
    "- 选择器 1 和 2 的唯一不同之处在于 `li:nth-child(n)` 的值（`nth-child(1)` 和 `nth-child(2)`）。这表示每个电影标题都遵循相同的结构，而 `li:nth-child(n)` 只是定位某个特定的电影条目。\n",
    "\n",
    "#### 通用选择器：\n",
    "\n",
    "通过移除 `nth-child(n)`，我们可以得到一个适用于所有电影条目的通用选择器：\n",
    "\n",
    "```css\n",
    "#content > div > div.article > ol > li > div > div.info > div.hd > a > span.title\n",
    "```\n",
    "\n",
    "该选择器会选中所有电影的标题，而不仅仅是第一个或第二个。\n",
    "\n",
    "### 推导后的代码解释：\n",
    "\n",
    "使用通用选择器，我们可以通过 `BeautifulSoup` 提取所有电影的标题：\n",
    "\n",
    "```python\n",
    "from bs4 import BeautifulSoup\n",
    "import requests\n",
    "\n",
    "# 设置请求的 URL\n",
    "url = \"https://movie.douban.com/top250\"\n",
    "\n",
    "# 定义请求头，模拟浏览器\n",
    "headers = {\n",
    "    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'\n",
    "}\n",
    "\n",
    "# 发送 GET 请求，获取页面内容\n",
    "response = requests.get(url, headers=headers)\n",
    "\n",
    "# 检查请求是否成功\n",
    "if response.status_code == 200:\n",
    "    html_content = response.text  # 获取网页 HTML 内容\n",
    "    \n",
    "    # 使用 BeautifulSoup 解析 HTML 内容\n",
    "    soup = BeautifulSoup(html_content, 'lxml')\n",
    "    \n",
    "    # 使用通用的 CSS 选择器提取所有电影的标题\n",
    "    movie_titles = soup.select('#content > div > div.article > ol > li > div > div.info > div.hd > a > span.title')\n",
    "    \n",
    "    # 打印所有提取到的电影标题\n",
    "    for title in movie_titles:\n",
    "        print(f\"电影名称: {title.text}\")\n",
    "else:\n",
    "    print(f\"请求失败，状态码: {response.status_code}\")\n",
    "```\n",
    "\n",
    "### 解释：\n",
    "\n",
    "- 通过 CSS 选择器 `#content > div > div.article > ol > li > div > div.info > div.hd > a > span.title`，我们可以提取所有电影条目中的标题，而不再局限于某个特定的电影条目。\n",
    "- `li` 是所有电影条目的通用选择器，因此我们可以用它循环遍历所有电影标题。\n",
    "\n",
    "### 结论：\n",
    "\n",
    "通过分析 `nth-child(1)` 和 `nth-child(2)` 的选择器，我们发现每个电影的结构相同，并通过通用选择器可以抓取所有电影标题。\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "72eb44e7-4491-41fc-93f4-58bece9876b7",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
